import 'dart:async';
import 'dart:io';
import 'dart:math' as math;
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:uuid/uuid.dart';
import 'package:mime/mime.dart';
import '../../../models/api_response.dart';
import '../../../models/chunk_upload.dart';
import '../../../config/upload_config.dart';
import '../utils/semaphore.dart';
import '../utils/cancel_token.dart';
import './chunk_upload_client.dart';

/// 上传任务管理器，负责管理上传任务队列
class UploadTaskManager {
  // 上传任务列表
  static final List<UploadTask> _uploadTasks = [];

  // 上传任务流控制器
  static final _uploadTasksController =
      StreamController<List<UploadTask>>.broadcast();

  // 获取上传任务流
  static Stream<List<UploadTask>> get uploadTasksStream =>
      _uploadTasksController.stream;

  // 获取上传任务列表
  static List<UploadTask> get uploadTasks => List.unmodifiable(_uploadTasks);

  // 单例模式实现
  static final UploadTaskManager _instance = UploadTaskManager._internal();
  factory UploadTaskManager() => _instance;
  UploadTaskManager._internal();

  // API客户端
  final _client = ChunkUploadClient();

  // 添加上传任务
  Future<(UploadTask task, bool isLargeFile)> addUploadTask({
    required String filePath,
    required String fileName,
    required int fileSize,
    required String mimeType,
    int directoryId = 0,
  }) async {
    print('准备添加上传任务: $fileName (${fileSize} 字节)');

    // 判断是否是大文件
    final isLargeFile = fileSize > UploadConfig.largeFileThreshold;
    final type = isLargeFile ? UploadTaskType.chunk : UploadTaskType.normal;

    print('文件类型: ${isLargeFile ? "大文件，使用断点续传" : "小文件，使用普通上传"}');

    // 生成唯一ID
    final id = const Uuid().v4();

    // 创建任务
    final task = UploadTask(
      id: id,
      fileName: fileName,
      filePath: filePath,
      fileSize: fileSize,
      mimeType: mimeType,
      type: type,
      status: UploadTaskStatus.pending,
      directoryId: directoryId,
    );

    print(
      '创建上传任务: ${task.fileName}, 大小: ${task.formattedSize}, 类型: ${task.type}',
    );

    // 添加到任务列表
    _uploadTasks.add(task);
    _notifyTasksChanged();

    return (task, isLargeFile);
  }

  // 开始上传任务
  Future<void> startUploadTask(String taskId) async {
    print('开始上传任务: $taskId');
    final taskIndex = _uploadTasks.indexWhere((task) => task.id == taskId);
    if (taskIndex == -1) {
      print('任务不存在: $taskId');
      return;
    }

    final task = _uploadTasks[taskIndex];

    print('任务类型: ${task.type == UploadTaskType.chunk ? "断点续传" : "普通上传"}');

    // 记录服务器任务ID信息，用于诊断
    if (task.type == UploadTaskType.chunk) {
      if (task.taskId != null) {
        print('任务具有服务器任务ID: ${task.taskId}，应当能够恢复上传');
      } else {
        print('任务没有服务器任务ID，将需要重新初始化');
      }
    }

    // 只有待上传、暂停或失败的任务可以开始
    if (task.status != UploadTaskStatus.pending &&
        task.status != UploadTaskStatus.paused &&
        task.status != UploadTaskStatus.failed) {
      print('任务状态不允许开始上传: ${task.status}');
      return;
    }

    // 保存重要的任务信息，包括服务器任务ID和原始状态
    final originalStatus = task.status; // 保存原始状态用于恢复逻辑
    final String? serverTaskId = task.taskId;
    final int? totalChunks = task.totalChunks;
    final int? uploadedChunks = task.uploadedChunks;

    try {
      // 预先将任务状态设置为uploading，除非它正在恢复(paused或failed且有taskId)
      // 这确保任务状态在进入处理逻辑前已经是uploading
      if (task.type == UploadTaskType.chunk) {
        print('开始断点续传任务: ${task.fileName}');

        // 断点续传任务，如果不是恢复状态，预先设置为uploading
        final isResuming =
            (originalStatus == UploadTaskStatus.paused ||
                originalStatus == UploadTaskStatus.failed) &&
            task.taskId != null;

        if (!isResuming) {
          print('非恢复状态的断点续传任务，预先设置状态为uploading');
          _updateTask(
            taskIndex,
            task.copyWith(status: UploadTaskStatus.uploading, error: null),
          );
          _notifyTasksChanged();
        }

        // 断点续传
        await _startChunkUpload(taskIndex);
      } else {
        print('开始普通上传任务: ${task.fileName}');

        // 普通上传前更新状态为上传中
        print('更新任务状态为上传中，普通上传任务');
        _updateTask(
          taskIndex,
          task.copyWith(status: UploadTaskStatus.uploading),
        );

        // 普通上传
        await _startNormalUpload(taskIndex);
      }
    } catch (e) {
      print('上传失败: $e');
      // 更新状态为失败
      if (taskIndex < _uploadTasks.length) {
        _updateTask(
          taskIndex,
          _uploadTasks[taskIndex].copyWith(
            status: UploadTaskStatus.failed,
            error: e.toString(),
          ),
        );
      }
    }
  }

  // 开始普通上传
  Future<void> _startNormalUpload(int taskIndex) async {
    if (taskIndex >= _uploadTasks.length) return;

    final task = _uploadTasks[taskIndex];
    print('开始普通上传，文件: ${task.fileName}, 目录ID: ${task.directoryId}');

    try {
      // 执行普通上传
      final response = await _client.uploadFile(
        filePath: task.filePath,
        directoryId: task.directoryId,
      );

      // 确保响应成功并包含数据
      if (response.isSuccess && response.data != null) {
        print('普通上传成功，设置响应数据');

        // 更新状态为完成
        final completedTask = task.copyWith(
          status: UploadTaskStatus.completed,
          progress: 100.0,
          completedAt: DateTime.now(),
          error: null,
          responseData: response.data, // 保存完整的响应数据
          uploadedBytes: task.fileSize, // 确保上传字节数正确
        );
        _updateTask(taskIndex, completedTask);

        // 强制通知任务状态更新
        _notifyTasksChanged();
      } else {
        throw Exception('上传响应无效: ${response.message}');
      }
    } catch (e) {
      print('上传失败: $e');
      // 更新状态为失败
      final failedTask = task.copyWith(
        status: UploadTaskStatus.failed,
        error: e.toString(),
      );
      _updateTask(taskIndex, failedTask);

      // 强制通知任务状态更新
      _notifyTasksChanged();
    }
  }

  // 开始分片上传
  Future<void> _startChunkUpload(int taskIndex) async {
    if (taskIndex >= _uploadTasks.length) return;

    final task = _uploadTasks[taskIndex];

    // 保存原始状态用于检查
    final originalStatus = task.status;
    final hasTaskId = task.taskId != null;
    final serverTaskId = task.taskId ?? ''; // 提供默认值避免空值

    print('开始分片上传，文件: ${task.fileName}, 目录ID: ${task.directoryId}');

    // 添加更详细的诊断日志
    print(
      '_startChunkUpload 诊断 - 任务ID=${task.id}, 当前状态=${task.status}, 原始状态=$originalStatus, 服务器任务ID=${task.taskId}',
    );
    print(
      '_startChunkUpload 诊断 - 暂停状态检查=${originalStatus == UploadTaskStatus.paused}',
    );
    print(
      '_startChunkUpload 诊断 - 失败状态检查=${originalStatus == UploadTaskStatus.failed}',
    );
    print('_startChunkUpload 诊断 - 服务器ID检查=$hasTaskId');
    print(
      '_startChunkUpload 诊断 - 总检查结果=${(originalStatus == UploadTaskStatus.paused || originalStatus == UploadTaskStatus.failed) && hasTaskId}',
    );

    try {
      String taskId;
      int totalChunks;
      int startFromChunk = 0;

      // 如果是暂停状态且已有 taskId，获取服务器状态
      if ((originalStatus == UploadTaskStatus.paused ||
              originalStatus == UploadTaskStatus.failed) &&
          hasTaskId) {
        print('从$originalStatus状态恢复，获取服务器端上传状态...');
        print('使用已有的服务器任务ID: $serverTaskId，当前进度: ${task.progress}%');

        try {
          // 设置超时时间，避免API长时间不响应
          final statusResponseFuture = _client.getUploadStatus(serverTaskId);
          final statusResponse = await statusResponseFuture.timeout(
            const Duration(seconds: 10),
            onTimeout: () {
              print('获取服务器状态超时，将尝试继续使用现有任务ID');
              // 返回一个构造的响应，保留本地记录的状态
              final localStatus = ChunkUploadStatusResponse.simplified(
                taskId: serverTaskId,
                totalChunks: task.totalChunks ?? 0,
                uploadedChunks: task.uploadedChunks ?? 0,
                progress: task.progress,
                directoryId: task.directoryId,
              );
              return ApiResponse(
                code: 200,
                message: '使用本地状态继续上传',
                data: localStatus,
                timestamp: DateTime.now().toIso8601String(),
              );
            },
          );

          if (!statusResponse.isSuccess || statusResponse.data == null) {
            print('获取上传状态失败: ${statusResponse.message}，尝试继续使用现有任务ID');
            // 使用本地状态而不是抛出异常
            final localStatus = ChunkUploadStatusResponse.simplified(
              taskId: serverTaskId,
              totalChunks: task.totalChunks ?? 0,
              uploadedChunks: task.uploadedChunks ?? 0,
              progress: task.progress,
              directoryId: task.directoryId,
            );
            taskId = serverTaskId;
            totalChunks = localStatus.totalChunks;
            startFromChunk = localStatus.uploadedChunks;
            print('使用本地记录继续上传: 总分片数=$totalChunks, 已上传分片数=$startFromChunk');
          } else {
            final serverStatus = statusResponse.data!;
            taskId = serverTaskId;
            totalChunks = serverStatus.totalChunks;
            startFromChunk = serverStatus.uploadedChunks;
            // 获取服务器返回的目录ID，如果没有则使用任务中的目录ID
            final directoryId =
                serverStatus.directoryId > 0
                    ? serverStatus.directoryId
                    : task.directoryId;

            // 如果服务器返回的已上传分片数小于本地记录，使用本地记录
            if (task.uploadedChunks != null &&
                task.uploadedChunks! > startFromChunk) {
              print(
                '服务器返回的已上传分片数($startFromChunk)小于本地记录(${task.uploadedChunks})，使用本地记录',
              );
              // 使用本地记录的上传进度，但保持服务器返回的总分片数
              startFromChunk = task.uploadedChunks!;
            }

            // 计算进度和已上传字节数
            final progress = (startFromChunk / totalChunks);
            final uploadedBytes = (progress * task.fileSize).round();

            print(
              '服务器状态获取成功: 总分片数=$totalChunks, 已上传分片数=$startFromChunk，进度=${progress * 100}%, 已上传字节数=${_formatFileSize(uploadedBytes)}, 目录ID=$directoryId',
            );

            // 更新本地任务状态
            _updateTask(
              taskIndex,
              task.copyWith(
                taskId: taskId,
                totalChunks: totalChunks,
                uploadedChunks: startFromChunk,
                progress: progress, // 进度值在0-1之间
                uploadedBytes: uploadedBytes, // 设置已上传字节数
                status: UploadTaskStatus.uploading, // 确保状态为上传中
                directoryId: directoryId, // 更新目录ID
              ),
            );
          }
        } catch (e) {
          print('恢复上传状态失败，但将继续使用现有任务ID: $e');
          // 使用本地状态继续上传
          taskId = serverTaskId;
          totalChunks = task.totalChunks ?? 0;
          startFromChunk = task.uploadedChunks ?? 0;

          // 如果本地没有记录分片信息，使用默认计算
          if (totalChunks == 0) {
            print('本地没有有效的分片信息，但有taskId=$serverTaskId，尝试直接恢复而不是重新初始化');

            // 改为使用默认值而不是重新初始化，因为重新初始化会导致断点续传失败
            totalChunks = math.max(
              1,
              (task.fileSize / UploadConfig.chunkSize).ceil(),
            );
            startFromChunk = 0;

            print('使用计算得到的分片信息：总分片数=$totalChunks，将尝试从第$startFromChunk个分片继续上传');
          } else {
            print('使用本地状态继续上传: 总分片数=$totalChunks, 已上传分片数=$startFromChunk');
          }

          // 计算进度和已上传字节数
          final progress = (startFromChunk / totalChunks);
          final uploadedBytes = (progress * task.fileSize).round();

          // 更新任务信息，设置上传中状态
          _updateTask(
            taskIndex,
            task.copyWith(
              taskId: taskId,
              totalChunks: totalChunks,
              uploadedChunks: startFromChunk,
              progress: progress, // 进度值在0-1之间
              uploadedBytes: uploadedBytes, // 设置已上传字节数
              status: UploadTaskStatus.uploading, // 设置为上传中状态
            ),
          );
        }
      } else {
        // 初始化新的分片上传
        print('初始化新的分片上传');

        // 先更新状态为上传中，并确保其他必要字段也被正确设置
        print('更新任务状态为上传中，准备初始化新任务');
        _updateTask(
          taskIndex,
          task.copyWith(
            status: UploadTaskStatus.uploading,
            progress: 0.0, // 确保进度从0开始
            uploadedChunks: 0, // 确保已上传分片数为0
            error: null, // 清除任何可能的错误信息
          ),
        );

        final initResponse = await _client.initChunkUpload(
          fileName: task.fileName,
          fileSize: task.fileSize,
          mimeType: task.mimeType,
          directoryId: task.directoryId,
        );

        if (!initResponse.isSuccess || initResponse.data == null) {
          throw Exception('初始化分片上传失败: ${initResponse.message}');
        }

        final initData = initResponse.data!;
        taskId = initData.taskId;
        totalChunks = initData.totalChunks;

        print('初始化上传成功，任务ID: $taskId, 总分片数: $totalChunks');

        // 更新任务信息
        _updateTask(
          taskIndex,
          task.copyWith(
            taskId: taskId,
            totalChunks: totalChunks,
            uploadedChunks: 0,
            status: UploadTaskStatus.uploading, // 确保状态为uploading
          ),
        );

        // 确保状态已更新后再进行_notifyTasksChanged
        _notifyTasksChanged();
      }

      // 创建取消上传的控制器
      final cancelToken = CancelToken();

      // 添加取消监听器，立即响应取消操作
      cancelToken.addListener(() {
        print('检测到取消操作通知，立即停止所有上传活动');
      });

      // 更新取消回调
      _updateTask(
        taskIndex,
        _uploadTasks[taskIndex].copyWith(
          cancelCallback: () async {
            print('取消回调被调用，立即停止所有上传操作');
            cancelToken.cancel(); // 触发取消操作
          },
        ),
      );

      // 上传所有分片
      await _uploadAllChunks(
        taskIndex: taskIndex,
        taskId: taskId,
        filePath: task.filePath,
        chunkSize: UploadConfig.chunkSize,
        totalChunks: totalChunks,
        cancelToken: cancelToken,
        startFromChunk: startFromChunk,
      );

      // 如果已取消，更新状态为暂停
      if (cancelToken.isCancelled) {
        print('上传已暂停，保存当前进度状态，任务ID: $taskId');

        // 查找对应的任务 - 优先按taskId查找，然后按任务索引查找
        int updatedTaskIndex = _uploadTasks.indexWhere(
          (task) => task.taskId == taskId,
        );

        // 如果找不到taskId匹配的任务，尝试使用原始任务索引
        if (updatedTaskIndex == -1 && taskIndex < _uploadTasks.length) {
          updatedTaskIndex = taskIndex;
          print('未找到匹配server taskId的任务，使用原始任务索引: $taskIndex');
        }

        if (updatedTaskIndex != -1) {
          final task = _uploadTasks[updatedTaskIndex];

          // 确保任务ID匹配
          if (task.taskId != taskId) {
            print('警告: 任务ID不匹配! 本地taskId=${task.taskId}, 服务器taskId=$taskId');
          }

          print(
            '更新任务状态为暂停: 任务ID=${task.id}, 服务器任务ID=$taskId, 上传进度=${task.progress}%',
          );

          // 保存上传状态并更新为暂停
          _updateTask(
            updatedTaskIndex,
            _uploadTasks[updatedTaskIndex].copyWith(
              status: UploadTaskStatus.paused,
              taskId: taskId, // 确保保存服务器taskId
              error: null,
            ),
          );

          // 强制通知更新
          _notifyTasksChanged();
        } else {
          print('严重错误: 无法找到要暂停的任务，本地taskIndex=$taskIndex, 服务器taskId=$taskId');
        }

        return;
      }

      // 完成上传
      print('准备完成上传...');
      final completeResponse = await _client.completeUpload(taskId);

      if (!completeResponse.isSuccess || completeResponse.data == null) {
        throw Exception('完成上传失败: ${completeResponse.message}');
      }

      print('上传完成，更新任务状态...');
      // 更新状态为完成
      if (taskIndex < _uploadTasks.length) {
        final completedTask = _uploadTasks[taskIndex].copyWith(
          status: UploadTaskStatus.completed,
          progress: 1.0, // 确保进度值在0-1之间
          completedAt: DateTime.now(),
          error: null,
        );
        print('更新任务状态为已完成');
        _updateTask(taskIndex, completedTask);

        // 强制触发任务列表更新
        _notifyTasksChanged();
      }
    } catch (e) {
      print('上传失败: $e');
      // 如果任务还存在，更新状态为失败
      if (taskIndex < _uploadTasks.length) {
        final failedTask = _uploadTasks[taskIndex].copyWith(
          status: UploadTaskStatus.failed,
          error: e.toString(),
        );
        _updateTask(taskIndex, failedTask);

        // 强制触发任务列表更新
        _notifyTasksChanged();
      }
    }
  }

  // 上传所有分片
  Future<void> _uploadAllChunks({
    required int taskIndex,
    required String taskId,
    required String filePath,
    required int chunkSize,
    required int totalChunks,
    required CancelToken cancelToken,
    int startFromChunk = 0,
  }) async {
    // 获取文件大小
    if (taskIndex >= _uploadTasks.length) {
      print('错误：上传任务索引超出范围');
      return;
    }

    final task = _uploadTasks[taskIndex];
    final fileSize = task.fileSize;

    // 计算已上传的字节数
    final initialUploadedBytes = (startFromChunk / totalChunks) * fileSize;

    // 更新任务的初始已上传字节数
    if (startFromChunk > 0) {
      _updateTask(
        taskIndex,
        task.copyWith(uploadedBytes: initialUploadedBytes.round()),
      );
    }

    print(
      '开始上传分片：文件=${task.fileName}, 大小=${task.formattedSize}, 从第$startFromChunk个分片开始, 总分片数=$totalChunks, 已上传=${_formatFileSize(initialUploadedBytes.round())}',
    );

    // 创建一个集合来存储已上传的分片
    final uploadedChunks = <int>{};
    // 先标记所有已上传的分片
    for (var i = 1; i <= startFromChunk; i++) {
      uploadedChunks.add(i);
    }

    print('已经上传了$startFromChunk个分片，仅需上传剩余的${totalChunks - startFromChunk}个分片');

    // 创建一个队列来存储待上传的分片 - 只包含未上传的分片
    final queue = <int>[];
    for (var i = startFromChunk + 1; i <= totalChunks; i++) {
      queue.add(i);
    }

    print('创建上传队列，总分片数=$totalChunks，待上传分片数=${queue.length}');

    // 创建一个字典来存储每个分片的重试次数
    final retryCount = <int, int>{};
    // 最大重试次数
    const maxRetries = 3;

    // 创建一个信号量来控制并发数
    final concurrentUploads = math.min(
      UploadConfig.defaultConcurrentUploads,
      queue.length,
    );
    print('设置并发上传数量: $concurrentUploads');
    final semaphore = Semaphore(concurrentUploads > 0 ? concurrentUploads : 1);

    // 创建一个列表来存储所有上传任务
    final uploadFutures = <Future<void>>[];

    // 上传开始时间，用于计算速度
    final startTime = DateTime.now().millisecondsSinceEpoch;
    var lastLogTime = startTime;
    var lastUploadedChunks = uploadedChunks.length;

    // 如果所有分片已上传完成，直接返回
    if (queue.isEmpty) {
      print('所有分片已上传完成，无需重新上传');
      // 更新进度为100%
      _updateTask(
        taskIndex,
        _uploadTasks[taskIndex].copyWith(
          progress: 1.0, // 确保进度值在0-1之间
          uploadedChunks: totalChunks,
          uploadedBytes: fileSize, // 设置已上传字节数为文件总大小
          status: UploadTaskStatus.completed, // 设置为已完成状态
        ),
      );
      return;
    }

    // 开始上传
    while (queue.isNotEmpty && !cancelToken.isCancelled) {
      // 获取下一个分片
      final chunkNumber = queue.removeAt(0);

      // 检查任务状态 - 仅在任务被明确取消或暂停时停止上传
      if (taskIndex < _uploadTasks.length) {
        final currentStatus = _uploadTasks[taskIndex].status;
        if (currentStatus == UploadTaskStatus.paused ||
            currentStatus == UploadTaskStatus.canceled ||
            currentStatus == UploadTaskStatus.failed) {
          print('检测到任务状态已变更为 $currentStatus，停止上传队列');
          // 标记取消以确保清理
          cancelToken.cancel();
          break;
        } else if (currentStatus == UploadTaskStatus.pending) {
          // 如果状态仍是pending，更新为uploading
          print('检测到任务状态仍为pending，更新为uploading');
          _updateTask(
            taskIndex,
            _uploadTasks[taskIndex].copyWith(
              status: UploadTaskStatus.uploading,
            ),
          );
        }
      }

      // 等待信号量
      await semaphore.acquire();

      // 如果已取消，释放信号量并退出
      if (cancelToken.isCancelled) {
        semaphore.release();
        print('信号量获取后检测到取消，释放并退出');
        break;
      }

      // 再次检查任务状态 - 与上面逻辑相同
      if (taskIndex < _uploadTasks.length) {
        final currentStatus = _uploadTasks[taskIndex].status;
        if (currentStatus == UploadTaskStatus.paused ||
            currentStatus == UploadTaskStatus.canceled ||
            currentStatus == UploadTaskStatus.failed) {
          semaphore.release();
          print('信号量获取后检测到任务状态变更，释放并退出');
          cancelToken.cancel();
          break;
        }
      }

      // 计算分片范围
      final start = (chunkNumber - 1) * chunkSize;
      final end = math.min(
        (chunkNumber == totalChunks) ? fileSize : start + chunkSize,
        fileSize,
      );

      // 创建上传任务
      final uploadFuture = _uploadChunk(
            taskIndex: taskIndex,
            taskId: taskId,
            chunkNumber: chunkNumber,
            filePath: filePath,
            start: start,
            end: end,
            cancelToken: cancelToken,
          )
          .then((success) {
            // 释放信号量
            semaphore.release();

            if (success) {
              // 添加到已上传集合
              uploadedChunks.add(chunkNumber);

              // 更新进度 - 确保进度值在0-1之间，而不是0-100之间
              final progress = (uploadedChunks.length / totalChunks);

              // 计算已上传字节数
              final uploadedBytes = (progress * fileSize).round();

              // 计算上传速度
              final now = DateTime.now().millisecondsSinceEpoch;
              final elapsed = now - lastLogTime;

              // 每2秒记录一次速度
              if (elapsed > 2000) {
                final chunksDelta = uploadedChunks.length - lastUploadedChunks;
                final bytesUploaded = chunksDelta * chunkSize;
                final speedKBps = (bytesUploaded / 1024) / (elapsed / 1000);

                print(
                  '上传进度: ${(progress * 100).toStringAsFixed(1)}%, 速度: ${speedKBps.toStringAsFixed(2)} KB/s, 已完成: ${uploadedChunks.length}/$totalChunks, 已上传: ${_formatFileSize(uploadedBytes)}',
                );

                lastLogTime = now;
                lastUploadedChunks = uploadedChunks.length;
              }

              _updateTask(
                taskIndex,
                _uploadTasks[taskIndex].copyWith(
                  progress: progress,
                  uploadedChunks: uploadedChunks.length,
                  uploadedBytes: uploadedBytes, // 更新已上传字节数
                ),
              );
            } else {
              // 如果上传失败且未取消，检查重试次数
              final currentRetries = retryCount[chunkNumber] ?? 0;
              if (currentRetries < maxRetries && !cancelToken.isCancelled) {
                // 增加重试次数并重新加入队列
                retryCount[chunkNumber] = currentRetries + 1;
                queue.add(chunkNumber);
                print('分片 $chunkNumber 上传失败，准备第 ${currentRetries + 1} 次重试');
              } else {
                print('分片 $chunkNumber 上传失败，已达到最大重试次数');
              }
            }
          })
          .catchError((e) {
            // 释放信号量
            semaphore.release();

            if (!cancelToken.isCancelled) {
              // 如果出错且未取消，检查重试次数
              final currentRetries = retryCount[chunkNumber] ?? 0;
              if (currentRetries < maxRetries) {
                // 增加重试次数并重新加入队列
                retryCount[chunkNumber] = currentRetries + 1;
                queue.add(chunkNumber);
                print('分片 $chunkNumber 上传出错：$e，准备第 ${currentRetries + 1} 次重试');
              } else {
                print('分片 $chunkNumber 上传出错：$e，已达到最大重试次数');
              }
            }
          });

      uploadFutures.add(uploadFuture);
    }

    // 等待所有上传任务完成
    await Future.wait(uploadFutures);

    // 记录最终的上传结果
    print('上传任务执行完毕，总分片数=$totalChunks，已上传分片数=${uploadedChunks.length}');

    // 如果已取消，更新状态为暂停
    if (cancelToken.isCancelled) {
      print('上传已暂停，保存当前进度状态，任务ID: $taskId');

      // 查找对应的任务 - 优先按taskId查找，然后按任务索引查找
      int updatedTaskIndex = _uploadTasks.indexWhere(
        (task) => task.taskId == taskId,
      );

      // 如果找不到taskId匹配的任务，尝试使用原始任务索引
      if (updatedTaskIndex == -1 && taskIndex < _uploadTasks.length) {
        updatedTaskIndex = taskIndex;
        print('未找到匹配server taskId的任务，使用原始任务索引: $taskIndex');
      }

      if (updatedTaskIndex != -1) {
        final task = _uploadTasks[updatedTaskIndex];

        // 确保任务ID匹配
        if (task.taskId != taskId) {
          print('警告: 任务ID不匹配! 本地taskId=${task.taskId}, 服务器taskId=$taskId');
        }

        print(
          '更新任务状态为暂停: 任务ID=${task.id}, 服务器任务ID=$taskId, 上传进度=${task.progress}%',
        );

        // 保存上传状态并更新为暂停
        _updateTask(
          updatedTaskIndex,
          _uploadTasks[updatedTaskIndex].copyWith(
            status: UploadTaskStatus.paused,
            taskId: taskId, // 确保保存服务器taskId
            error: null,
          ),
        );

        // 强制通知更新
        _notifyTasksChanged();
      } else {
        print('严重错误: 无法找到要暂停的任务，本地taskIndex=$taskIndex, 服务器taskId=$taskId');
      }

      return;
    }

    // 检查成功上传的分片数量
    final successRate = (uploadedChunks.length / totalChunks).toDouble();
    print('分片上传完成率: ${(successRate * 100).toStringAsFixed(2)}%');

    // 删除原来的完成率检查代码，避免任务自动进入暂停状态
    if (uploadedChunks.length < totalChunks) {
      print('未上传全部分片: ${uploadedChunks.length}/$totalChunks，但未检测到取消操作，继续完成上传');

      // 更新任务状态，但不设为失败或暂停
      _updateTask(
        taskIndex,
        _uploadTasks[taskIndex].copyWith(
          progress: (uploadedChunks.length / totalChunks) * 100,
          uploadedChunks: uploadedChunks.length,
        ),
      );
    }
  }

  // 上传单个分片
  Future<bool> _uploadChunk({
    required int taskIndex,
    required String taskId,
    required int chunkNumber,
    required String filePath,
    required int start,
    required int end,
    CancelToken? cancelToken,
  }) async {
    try {
      // 检查是否已取消
      if (cancelToken?.isCancelled == true) {
        print('上传前检测到取消请求，跳过分片 $chunkNumber');
        return false;
      }

      print(
        '开始上传分片：taskId=$taskId, chunkNumber=$chunkNumber, start=$start, end=$end',
      );

      if (!kIsWeb) {
        final file = File(filePath);
        if (!await file.exists()) {
          throw Exception('文件不存在：$filePath');
        }

        // 再次检查是否已取消
        if (cancelToken?.isCancelled == true) {
          print('读取文件前检测到取消请求，跳过分片 $chunkNumber');
          return false;
        }

        // 读取指定范围的字节
        final chunkData = await _readFileChunk(file, start, end);

        // 再次检查是否已取消
        if (cancelToken?.isCancelled == true) {
          print('准备上传前检测到取消请求，跳过分片 $chunkNumber');
          return false;
        }

        // 上传分片
        final response = await _client.uploadChunk(
          taskId: taskId,
          chunkNumber: chunkNumber,
          chunkData: chunkData,
          filePath: filePath,
          start: start,
          end: end,
        );

        return response.isSuccess;
      } else {
        throw Exception('Web平台暂不支持分片上传');
      }
    } catch (e) {
      // 错误时也检查取消状态，避免报告不必要的错误
      if (cancelToken?.isCancelled == true) {
        print('发生错误时检测到已取消，不报告错误: $chunkNumber');
        return false;
      }
      print('上传分片 $chunkNumber 失败: $e');
      return false;
    }
  }

  // 读取文件分片
  Future<Uint8List> _readFileChunk(File file, int start, int end) async {
    final chunkSize = end - start;
    final fileStream = file.openRead(start, end);

    final chunks = <List<int>>[];
    var currentSize = 0;

    await for (var chunk in fileStream) {
      chunks.add(chunk);
      currentSize += chunk.length;
    }

    // 合并所有数据块
    final result = Uint8List(currentSize);
    var offset = 0;
    for (var chunk in chunks) {
      result.setRange(offset, offset + chunk.length, chunk);
      offset += chunk.length;
    }

    return result;
  }

  // 暂停上传任务
  Future<void> pauseUploadTask(String taskId) async {
    final taskIndex = _uploadTasks.indexWhere((task) => task.id == taskId);
    if (taskIndex == -1) {
      print('任务不存在，无法暂停: $taskId');
      return;
    }

    final task = _uploadTasks[taskIndex];
    print('准备暂停任务: ${task.id}, 当前状态: ${task.status}, 服务器任务ID: ${task.taskId}');

    // 添加一个标志，表示此任务正在暂停过程中
    _updateTask(
      taskIndex,
      task.copyWith(
        status: UploadTaskStatus.paused, // 立即将状态设置为暂停，阻止新的分片上传
        error: '正在暂停中...',
      ),
    );
    // 立即通知状态变化，让UI响应
    _notifyTasksChanged();

    print('已将任务状态设置为暂停中，停止新分片上传');

    // 如果任务正在上传中，调用取消回调停止当前上传
    if (task.cancelCallback != null) {
      print('调用取消回调停止上传');
      await task.cancelCallback!();

      // 等待片刻，确保取消操作有时间生效
      await Future.delayed(const Duration(milliseconds: 500));
      print('取消回调已执行，等待上传停止');
    }

    // 确保保存了服务器taskId
    String? serverTaskId = task.taskId;
    if (serverTaskId == null) {
      print('警告：暂停时服务器任务ID为空，将无法正确恢复上传！');
    } else {
      print('正在暂停任务，服务器任务ID: $serverTaskId，将用于后续恢复');
    }

    // 更新状态为暂停，保留所有进度信息，不调用服务器的取消接口
    print('更新任务状态为暂停，保留进度信息');
    _updateTask(
      taskIndex,
      task.copyWith(
        status: UploadTaskStatus.paused,
        taskId: serverTaskId, // 确保保留taskId
        totalChunks: task.totalChunks,
        uploadedChunks: task.uploadedChunks,
        progress: task.progress,
        error: null,
      ),
    );

    // 强制通知任务状态更新
    _notifyTasksChanged();
    print('任务已暂停: $taskId, 服务器任务ID: ${task.taskId}');
  }

  // 恢复上传任务
  Future<void> resumeUploadTask(String taskId) async {
    final taskIndex = _uploadTasks.indexWhere((task) => task.id == taskId);
    if (taskIndex == -1) {
      print('任务不存在，无法恢复: $taskId');
      return;
    }

    final task = _uploadTasks[taskIndex];
    print('准备恢复任务: ${task.id}, 当前状态: ${task.status}, 服务器任务ID: ${task.taskId}');

    // 添加详细状态日志，诊断问题
    print('诊断信息 - 恢复任务: taskId=${task.id}');
    print(
      '诊断信息 - 状态检查: ${task.status == UploadTaskStatus.paused ? "是暂停状态" : "不是暂停状态"}',
    );
    print(
      '诊断信息 - 状态检查: ${task.status == UploadTaskStatus.failed ? "是失败状态" : "不是失败状态"}',
    );
    print(
      '诊断信息 - taskId检查: ${task.taskId != null ? "taskId存在: ${task.taskId}" : "taskId为空"}',
    );
    print(
      '诊断信息 - 暂停条件: ${(task.status == UploadTaskStatus.paused || task.status == UploadTaskStatus.failed) && task.taskId != null ? "满足恢复条件" : "不满足恢复条件"}',
    );

    // 只有暂停或失败的任务可以恢复
    if (task.status != UploadTaskStatus.paused &&
        task.status != UploadTaskStatus.failed) {
      print('任务状态不允许恢复: ${task.status}');
      return;
    }

    // 验证任务类型和必要条件
    if (task.type == UploadTaskType.chunk && task.taskId == null) {
      print('警告: 分片上传任务没有服务器任务ID，将需要重新初始化');
    }

    // 清除错误，但不更改状态（让startUploadTask负责更新状态）
    if (task.error != null) {
      print('清除任务错误信息');
      _updateTask(taskIndex, task.copyWith(error: null));

      // 通知任务状态更新
      _notifyTasksChanged();
    }

    // 开始上传任务
    print('开始恢复上传任务: $taskId');
    await startUploadTask(taskId);
  }

  // 取消上传任务
  Future<void> cancelUploadTask(String taskId) async {
    final taskIndex = _uploadTasks.indexWhere((task) => task.id == taskId);
    if (taskIndex == -1) return;

    final task = _uploadTasks[taskIndex];

    // 如果任务正在上传中，调用取消回调
    if (task.status == UploadTaskStatus.uploading &&
        task.cancelCallback != null) {
      task.cancelCallback!();
    }

    // 如果是分片上传且有taskId，取消服务器上的任务
    if (task.type == UploadTaskType.chunk && task.taskId != null) {
      try {
        await _client.abortUpload(task.taskId!);
      } catch (e) {
        print('取消服务器上传任务失败: $e');
        // 继续执行，即使服务器端取消失败也要更新本地状态
      }
    }

    // 更新状态为取消
    _updateTask(taskIndex, task.copyWith(status: UploadTaskStatus.canceled));
  }

  // 移除上传任务
  void removeUploadTask(String taskId) {
    final taskIndex = _uploadTasks.indexWhere((task) => task.id == taskId);
    if (taskIndex == -1) return;

    final task = _uploadTasks[taskIndex];

    // 如果任务正在上传中，先取消
    if (task.status == UploadTaskStatus.uploading) {
      cancelUploadTask(taskId);
    }

    // 从列表中移除
    _uploadTasks.removeAt(taskIndex);
    _notifyTasksChanged();
  }

  // 清除已完成的任务
  void clearCompletedTasks() {
    _uploadTasks.removeWhere(
      (task) =>
          task.status == UploadTaskStatus.completed ||
          task.status == UploadTaskStatus.canceled,
    );
    _notifyTasksChanged();
  }

  // 创建上传任务
  Future<UploadTask> createUploadTask(String filePath) async {
    // 获取文件信息
    final file = File(filePath);
    if (!file.existsSync()) {
      throw Exception('文件不存在: $filePath');
    }

    // 获取文件名和大小
    final fileName = file.path.split('/').last;
    final fileSize = file.lengthSync();

    // 估计MIME类型
    final mimeType = lookupMimeType(filePath) ?? 'application/octet-stream';

    // 生成任务ID
    final id = const Uuid().v4();

    // 创建上传任务
    return UploadTask(
      id: id,
      fileName: fileName,
      filePath: filePath,
      fileSize: fileSize,
      mimeType: mimeType,
      type:
          fileSize > UploadConfig.largeFileThreshold
              ? UploadTaskType.chunk
              : UploadTaskType.normal,
      status: UploadTaskStatus.pending,
      directoryId: 0, // 默认上传到根目录
    );
  }

  // 上传完整文件（方便外部调用）
  Future<void> uploadFile({
    required File file,
    required String filename,
    required int directoryId,
    Function(double)? onProgress,
  }) async {
    debugPrint('准备上传文件: $filename, 目录ID: $directoryId');

    try {
      // 文件大小
      final fileSize = await file.length();

      // 获取MIME类型
      final mimeType = lookupMimeType(file.path) ?? 'application/octet-stream';

      // 初始化上传任务
      final (task, _) = await addUploadTask(
        filePath: file.path,
        fileName: filename,
        fileSize: fileSize,
        mimeType: mimeType,
        directoryId: directoryId,
      );

      // 上传开始时间
      final startTime = DateTime.now().millisecondsSinceEpoch;

      // 监听上传进度
      if (onProgress != null) {
        Timer.periodic(const Duration(milliseconds: 500), (timer) {
          // 获取任务状态
          final currentTask = _uploadTasks.firstWhere(
            (t) => t.id == task.id,
            orElse: () => task,
          );

          // 计算进度
          if (currentTask.status == UploadTaskStatus.uploading) {
            final progress =
                (currentTask.uploadedBytes / currentTask.fileSize).toDouble();
            onProgress(progress);
          } else if (currentTask.status == UploadTaskStatus.completed ||
              currentTask.status == UploadTaskStatus.failed ||
              currentTask.status == UploadTaskStatus.canceled) {
            // 上传完成或失败，取消定时器
            timer.cancel();

            // 完成时回调进度100%
            if (currentTask.status == UploadTaskStatus.completed) {
              onProgress(1.0);
            }
          }
        });
      }

      // 开始上传
      await startUploadTask(task.id);

      // 等待上传完成
      await _waitForUploadCompletion(task.id);

      // 计算总用时
      final endTime = DateTime.now().millisecondsSinceEpoch;
      final duration = (endTime - startTime) / 1000;

      debugPrint('文件上传完成: $filename, 用时: ${duration.toStringAsFixed(1)}秒');
    } catch (e) {
      debugPrint('文件上传失败: $e');
      rethrow;
    }
  }

  // 等待上传完成
  Future<void> _waitForUploadCompletion(String taskId) async {
    // 最大等待时间 10 分钟
    final maxWaitTime = Duration(minutes: 10);
    final startTime = DateTime.now();

    while (true) {
      // 检查是否超时
      if (DateTime.now().difference(startTime) > maxWaitTime) {
        throw Exception('上传超时');
      }

      // 查找任务
      final taskIndex = _uploadTasks.indexWhere((task) => task.id == taskId);

      // 任务不存在
      if (taskIndex == -1) {
        throw Exception('上传任务不存在');
      }

      final task = _uploadTasks[taskIndex];

      // 上传完成
      if (task.status == UploadTaskStatus.completed) {
        return;
      }

      // 上传失败
      if (task.status == UploadTaskStatus.failed ||
          task.status == UploadTaskStatus.canceled) {
        throw Exception('上传失败: ${task.error ?? "未知错误"}');
      }

      // 等待一段时间后再检查
      await Future.delayed(Duration(milliseconds: 300));
    }
  }

  // 更新任务
  void _updateTask(int index, UploadTask newTask) {
    if (index >= 0 && index < _uploadTasks.length) {
      _uploadTasks[index] = newTask;
      _notifyTasksChanged();
    }
  }

  // 通知任务列表更新
  void _notifyTasksChanged() {
    if (!_uploadTasksController.isClosed) {
      final tasks = List<UploadTask>.from(_uploadTasks);
      _uploadTasksController.add(List.unmodifiable(tasks));
    }
  }

  // 销毁
  void dispose() {
    _uploadTasksController.close();
  }

  // 格式化文件大小的辅助方法
  String _formatFileSize(int size) {
    if (size < 1024) return '$size B';
    if (size < 1024 * 1024) return '${(size / 1024).toStringAsFixed(1)} KB';
    if (size < 1024 * 1024 * 1024) {
      return '${(size / (1024 * 1024)).toStringAsFixed(1)} MB';
    }
    return '${(size / (1024 * 1024 * 1024)).toStringAsFixed(1)} GB';
  }
}
